﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data;
using System.Linq;
using AxeFrog.Data;

namespace AxeFrog.Security.Data.MSSQL
{
	[Export("MSSQL", typeof(IUserRepository))]
	[Export("MSSQL", typeof(IRepository<User,long>))]
	public class UserRepository : Repository<User, long>, IUserRepository
	{
		public User GetByUsername(string username)
		{
			using (var cc = Connect())
				return cc.Select<User, long>(u => u.Username == username && !u.Deleted);
		}

		public User GetByEmail(string email)
		{
			using (var cc = Connect())
				return cc.Select<User, long>(u => u.Email == email && !u.Deleted);
		}

		public bool CheckForOtherUserByName(string name, long currentUserID)
		{
			using (var cc = Connect())
				return cc.Count<User, long>(u => u.Name == name && u.ID != currentUserID && !u.Deleted) > 0;
		}

		public bool CheckForOtherUserByEmail(string email, long currentUserID)
		{
			using (var cc = Connect())
				return cc.Count<User, long>(u => u.Email == email && u.ID != currentUserID && !u.Deleted) > 0;
		}

		public bool CheckForOtherUserByUsername(string username, long currentUserID)
		{
			using (var cc = Connect())
				return cc.Count<User, long>(u => u.Username == username && u.ID != currentUserID && !u.Deleted) > 0;
		}

		public DataPage<User> List()
		{
			return List(new UserQueryOptions());
		}

		public DataPage<User> List(UserQueryOptions options)
		{
			using (var cc = Connect())
			{
				var results = new DataPage<User> { Records = new List<User>() };
				return cc.CreateProcedure("ListUsers")
					.AddParameter("@PageSize", options.PageSize, DbType.Int32)
					.AddParameter("@PageNumber", options.PageNumber, DbType.Int32)
					.AddParameter("@Deleted", options.Deleted, DbType.Boolean)
					.AddParameter("@Search", options.Search, DbType.String)
					.AddParameter("@OrderByField", options.OrderBy, DbType.Int32)
					.AddParameter("@OrderByAscending", options.OrderByAscending, DbType.Boolean)
					.ExecuteReader()
					.ReadEach(reader => results.Records.Add(reader.MapTo<User>()))
					.NextResultSet()
					.ReadNext()
					.Do(reader => {
					              	results.PageSize = Convert.ToInt32(reader["PageSize"]);
					              	results.PageNumber = Convert.ToInt32(reader["PageNumber"]);
					              	results.TotalPages = Convert.ToInt32(reader["TotalPages"]);
					              	results.TotalRecords = Convert.ToInt32(reader["TotalRecords"]);
					})
					.Return(results);
			}
		}

		public int CountNewUsers(int days)
		{
			using (var cc = Connect())
				return cc.CreateCommand(@"SELECT COUNT(*) FROM [User]
										  WHERE Deleted = 0 AND DATEDIFF(d, DateCreated, GETUTCDATE()) <= @Days")
					.AddParameter("@Days", days)
					.ExecuteReader()
					.ReadAndReturn<int>();
		}

		public int CountUsersInRole(long role)
		{
			using (var cc = Connect())
				return cc.CreateCommand(@"SELECT COUNT(*) FROM [User] u
										  INNER JOIN [RoleMembership] m ON u.ID = m.UserID
										  WHERE Deleted = 0 AND m.RoleID = @RoleID")
					.AddParameter("@RoleID", role)
					.ExecuteReader()
					.ReadAndReturn<int>();
		}

		public int CountUsers()
		{
			using(var cc = Connect())
				return cc.Count<User, long>(u => !u.Deleted);
		}

		public void NotifyUserAccess(User user)
		{
		}
	}
}